/**
 * 
 */
package edu.cmu.aes.project1.app2;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * @author swasanta
 * 
 */
public class XMLConsolidation {

	public static String xmlsPath = "output/app1/";

	/**
	 * This method get a list of files in folder of output from application 1
	 * 
	 * @return a array of path file
	 */
	private static String[] getListOfFiles() {

		String[] files = new String[0];
		File dir = new File(xmlsPath);

		if (dir.exists() && dir.isDirectory()) {
			String[] children = dir.list();
			ArrayList<String> paths = new ArrayList<String>();
			
			for (int i = 0; i < children.length; i++) {
				if (children[i].endsWith(".xml"))
					paths.add(xmlsPath + children[i]);
			}
			
			files = paths.toArray(new String[paths.size()]);
		}

		return files;
	}

	private static void readByFile(Document rootDocument, Node root,
			String filePath) {

		DocumentBuilderFactory builderFactory = DocumentBuilderFactory
				.newInstance();

		try {
			File file = new File(filePath);

			InputStream xmlStream = new FileInputStream(file);

			builderFactory.setNamespaceAware(true); // never forget this!
			DocumentBuilder builder = builderFactory.newDocumentBuilder();
			Document document = builder.parse(xmlStream);

			Node rootOfFile = document.getFirstChild();

			NamedNodeMap rootAttribute = rootOfFile.getAttributes();
			Node attrNode = rootAttribute.getNamedItem("name");
			String manufacturerName = attrNode.getNodeValue();

			attrNode = rootAttribute.getNamedItem("year");
			String manufacturerYear = attrNode.getNodeValue();

			XPathFactory xPathFactory = XPathFactory.newInstance();
			XPath xpath = xPathFactory.newXPath();
			XPathExpression expr = xpath.compile("/manufacturer/model");
			Object result = expr.evaluate(document, XPathConstants.NODESET);
			NodeList nodes = (NodeList) result;

			// Document newDocument = builder.newDocument();
			// Element newRoot = newDocument.createElement("models");
			if (nodes.getLength() > 0) {
				for (int i = 0; i < nodes.getLength(); i++) {
					Node node = nodes.item(i);
					Node newNode = rootDocument.adoptNode(node.cloneNode(true));

					Node yearNode = rootDocument.createElement("year");
					yearNode.appendChild(rootDocument
							.createTextNode(manufacturerYear));

					newNode.insertBefore(yearNode, newNode.getFirstChild());

					Node manufacturerNode = rootDocument
							.createElement("manufacturer");
					manufacturerNode.appendChild(rootDocument
							.createTextNode(manufacturerName));

					newNode.insertBefore(manufacturerNode,
							newNode.getFirstChild());

					root.appendChild(newNode);
				}
			}

		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (XPathExpressionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	// This method writes a DOM document to a file
	public static void writeXmlFile(Document doc, String filename) {
		try {
			// Prepare the DOM document for writing
			Source source = new DOMSource(doc);

			// Prepare the output file
			File file = new File(filename);
			File fileDirectory = new File(file.getParent());
			if (!fileDirectory.exists())
				fileDirectory.mkdirs();

			Result result = new StreamResult(file);

			// Write the DOM document to the file
			Transformer xformer = TransformerFactory.newInstance()
					.newTransformer();
			xformer.transform(source, result);
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}

	public static boolean consolidateXMLs() {
		String[] files = getListOfFiles();
		
		System.out.println("Start consolidating XML files");
		try {
			boolean isFirst = true;
			 

			Node root = null; 
			for (String filePath : files) {
				DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
				DocumentBuilder builder = builderFactory.newDocumentBuilder();
				Document newDocument = null;
				
				if(isFirst){
					newDocument = builder.newDocument();
					root = newDocument.createElement("models");
				}else{
					newDocument = builder.parse(new File("output/app2/consolidated_data.xml"));
					root = newDocument.getFirstChild();
				}
				
				readByFile(newDocument, root, filePath);
				
				if(isFirst){
					newDocument.appendChild(root);
					isFirst = false;
				}
				writeXmlFile(newDocument, "output/app2/consolidated_data.xml");
			}
			
			//System.out.println("# of child" + newDocument.getFirstChild().getChildNodes().getLength());
			System.out.println("Consolidation is finished");

		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

	public static void main(String[] args) {
		consolidateXMLs();
	}
}
